use crate::physical_plan::PhysicalPlanExprArg;
use crate::data_frame::{value::{RealValue, RealValueType}};
use crate::run_plan::HandResult;
use crate::lazy_static::__Deref;
use std::sync::Arc;
use crate::physical_plan::window::SortByValue;
use crate::data_frame::single_data::SingleData;

pub fn get_element(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 1{
        return HandResult::Err(());
    }

    let key = &args[0];
    match key.deref(){
        PhysicalPlanExprArg::RealValue(_) => {return HandResult::Err(());},
        PhysicalPlanExprArg::ConfValue(_) => {return HandResult::Err(());},
        PhysicalPlanExprArg::ElementValue(key) => {
            return HandResult::Ok(data.get_key_value_always(key));
        },
    }
}

pub fn add_element(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 2{
        return HandResult::Err(());
    }

    let left = &args[0];
    let right = &args[1];

    match left.deref() {
        PhysicalPlanExprArg::ElementValue(left) => {
            match right.deref(){
                PhysicalPlanExprArg::ElementValue(right) => {
                    let right = &data.data.get_key_value(right)?;

                    let mut tmp_data = data.data.deref().clone();

                    let res =  tmp_data.set_key_value(left, right.clone());
                    data.data = Arc::from(tmp_data);

                    return res;
                },
                PhysicalPlanExprArg::RealValue(right) => {
                    let mut tmp_data = data.data.deref().clone();

                    let res = tmp_data.set_key_value(left, right.clone());
                    data.data = Arc::from(tmp_data);

                    return res;
                },
                PhysicalPlanExprArg::ConfValue(right) => {
                    return HandResult::Err(());
                },
            }
        },
        _ => {
            return HandResult::Err(());
        },
    }
}

pub fn element_exist(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 1{
        return HandResult::Err(());
    }

    let element = &args[0];

    match element.deref() {
        PhysicalPlanExprArg::ElementValue(left) => {
            return data.data.key_exist(left);
        },
        _ => {
            return HandResult::Err(());
        },
    }
}

pub fn convert(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 2{
        return HandResult::Err(());
    }

    let element = &args[0];
    let new_type = &args[1];

    match element.deref() {
        PhysicalPlanExprArg::ElementValue(element) => {
            match new_type.deref() {
                PhysicalPlanExprArg::ConfValue(new_type) => {
                    let mut tmp_data = data.data.deref().clone();
                    match tmp_data.convert_value(element, RealValueType::from_str(new_type.value.as_str())) {
                        Ok(_) => {
                            data.data = Arc::from(tmp_data);
                            return HandResult::Ok(RealValue::None);
                        },
                        _ => {
                            return HandResult::Err(());
                        }
                    }
                },
                _ => {
                    return HandResult::Err(());
                },
            }
        },
        _ => {
            return HandResult::Err(());
        },
    }
}

pub fn encode(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 1{
        return HandResult::Err(());
    }

    let element = &args[0];

    match element.deref() {
        PhysicalPlanExprArg::ElementValue(element) => {
            let mut tmp_data = data.data.deref().clone();
            match tmp_data.encode_value(element) {
                Ok(_) => {
                    data.data = Arc::from(tmp_data);
                    return HandResult::Ok(RealValue::None);
                },
                _ => {
                    return HandResult::Err(());
                }
            }
        },
        _ => {
            return HandResult::Err(());
        }
    }
}

pub fn decode(args: &[Box<PhysicalPlanExprArg>], data: &mut SingleData) -> HandResult {
    if args.len() != 1{
        return HandResult::Err(());
    }

    let element = &args[0];

    match element.deref() {
        PhysicalPlanExprArg::ElementValue(element) => {
            let mut tmp_data = data.data.deref().clone();
            match tmp_data.decode_value(element) {
                Ok(_) => {
                    data.data = Arc::from(tmp_data);
                    return HandResult::Ok(RealValue::None);
                },
                _ => {
                    return HandResult::Err(());
                }
            }
        },
        _ => {
            return HandResult::Err(());
        }
    }
}
